﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using WebSocketChat.Common.Database;

namespace WebSocketChat.Common.Server
{
    public class ServerSocket
    {
        public static Socket LocalSocket = null;
        public static ConcurrentDictionary<string, SocketUser> Users = new ConcurrentDictionary<string, SocketUser>();

        public event Action<MessageArriveEventArgs> MessageArrive;
        public event Action<CloseEventArgs> OnClose;
        private Helper dbContext;

        public Helper DbContext
        {
            get
            {
                if (dbContext == null)
                    dbContext = new Helper();
                return dbContext;
            }
        }


        /// <summary>
        /// 创建Socket
        /// </summary>
        /// <param name="port">端口默认 11011</param>
        /// <param name="backlog">The maximum length of the pending connections queue.</param>
        /// <returns></returns>
        public Socket Create(int port = 11011, int backlog = 100)
        {
            if (LocalSocket == null)
            {
                IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, port);//本机预使用的IP和端口
                LocalSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                LocalSocket.Bind(ipEndPoint);
                LocalSocket.Listen(backlog);
            }
            return LocalSocket;
        }

        /// <summary>
        /// 查找客户端连接
        /// </summary>
        /// <param name="id">标识</param>
        /// <returns></returns>
        private Socket FindClient(string ep)
        {
            foreach (var item in Users)
            {
                if (item.Key.ToString() == ep)
                    return item.Value.Socket;
            }
            return null;
        }

        private ChatUser FindClientUser(string ep)
        {
            foreach (var item in Users)
            {
                if (item.Key.ToString() == ep)
                    return item.Value.User;
            }
            return null;
        }

        private Socket FindClient(ChatUser user)
        {
            try
            {
                foreach (var item in Users)
                {
                    if (item.Value.User.ID == user.ID)
                        return item.Value.Socket;
                }
            }
            catch (Exception ex)
            {
                return null;
            }
            return null;
        }

        private Socket FindClient(int userID)
        {
            try
            {
                foreach (var item in Users)
                {
                    if (item.Value.User.ID == userID)
                        return item.Value.Socket;
                }
            }
            catch (Exception ex)
            {
                return null;
            }
            return null;
        }

        public void Receive(object client)
        {
            Socket param = client as Socket;
            if (param != null)
            {
                var remoteName = param.RemoteEndPoint.ToString();
                int count = 0;
                while (true)
                {
                    byte[] buffer = null;
                    try
                    {
                        if (param.Connected == false)
                        {
                            MessageArrive?.Invoke(new MessageArriveEventArgs()
                            {
                                Current = param,
                                Message = new CommandMessage()
                                {
                                    Type = MessageType.Offline,
                                    Data = FindClientUser(remoteName)
                                }
                            });
                            return;
                        }
                        buffer = new byte[1024 * 1024];
                        count = param.Receive(buffer);
                        MessageArrive?.Invoke(new MessageArriveEventArgs()
                        {
                            Message = MessageConvert.Parse(buffer, count),
                            Current = param
                        });
                    }
                    catch (SocketException ex)
                    {
                        if (ex.SocketErrorCode == SocketError.ConnectionReset)
                        {
                            MessageArrive?.Invoke(new MessageArriveEventArgs()
                            {
                                Current = param,
                                Message = new CommandMessage()
                                {
                                    Type = MessageType.Offline,
                                    Data = FindClientUser(remoteName)
                                }
                            });
                            return;
                        }
                        else
                        {
                            //WriteLog(remoteName + ex.Message);
                        }
                    }

                    if (count == 0)
                    {
                        MessageArrive?.Invoke(new MessageArriveEventArgs()
                        {
                            Current = param,
                            Message = new CommandMessage()
                            {
                                Type = MessageType.Offline,
                                Data = FindClientUser(remoteName)
                            }
                        });
                        return;
                    }
                }
            }
        }

        /// <summary>
        /// 接受远程连接
        /// </summary>
        public void Accept()
        {
            if (LocalSocket != null)
            {
                while (true)
                {
                    Socket client = LocalSocket.Accept();
                    Thread thread = new Thread(new ParameterizedThreadStart(Receive));
                    thread.Start(client);
                }
            }
        }

        public void Close()
        {
            
        }

        public bool Transport(IMessage msg)
        {
            var socket = FindClient(msg.Receiver);
            if (socket != null)//如果未找到用户
            {
                socket.Send(msg.Serialize());
                return true;
            }
            else//尝试从web中查找
            {
                return false;
            }
        }

        /// <summary>
        /// 广播
        /// </summary>
        /// <param name="info">信息</param>
        public void Broadcast(IMessage msg)
        {
            foreach (var item in Users)
            {
                try
                {
                    if (item.Value != null && item.Value.Socket != null)
                    {
                        item.Value.Socket.Send(msg.Serialize(true));
                    }
                }
                catch (Exception ex)
                {
                    continue;
                }
            }
        }

        public void BroadcastFriend(int id, IMessage msg)
        {
            var uids = DbContext.GetFriendIds(id);
            foreach (var item in Users)
            {
                try
                {
                    if (item.Value != null && item.Value.Socket != null && uids.Contains(item.Value.User.ID))
                    {
                        item.Value.Socket.Send(msg.Serialize());
                    }
                }
                catch (Exception ex)
                {
                    continue;
                }
            }
        }

        /// <summary>
        /// 移除已经登录的用户
        /// 重复登录检查
        /// </summary>
        /// <param name="user">用户</param>
        public void SingleLogin(ChatUser user)
        {
            string key = string.Empty;
            foreach (var item in Users)
            {
                if (item.Value.User != null & item.Value.User.ID == user.ID)
                {
                    key = item.Key;
                    //WriteLog(item.Value.User.EmployeeNO + "重复登录被移除");
                    IMessage msg = new CommandMessage()
                    {
                        Data = user,
                        Receiver = user.ID,
                        Type = MessageType.Offline
                    };
                    item.Value.Socket.Send(msg.Serialize());
                }
            }
            if (!string.IsNullOrEmpty(key))
            {
                SocketUser su;
                Users.TryRemove(key, out su);
            }
        }

    }

    public class MessageArriveEventArgs : EventArgs
    {
        public Socket Current { get; set; }
        public IMessage Message { get; set; }
    }

    public class CloseEventArgs : EventArgs
    {
        public string ep { get; set; }
    }
}
